﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using eTerm.PlugIn.NCore;
using eTerm.MsSql.DbProvider;
using eTerm.ASynClientSDK;
using System.Text.RegularExpressions;

namespace eTerm.PlugIn.AutoSeatPNR
{
    public class PNRModePlugIn : BaseSocketPlugIn, IPlugIn
    {
        /// <summary>
        /// 差件名称
        /// </summary>
        /// <value>用于日志记录的插件名称.</value>
        public override string PlugInName
        {
            get
            {
                return @"PNR编码方式预订航班";
            }
        }


        private Queue<PnrRequire> __PnrQueue = new Queue<PnrRequire>();
        private PnrSegment __CurrentSegment = null;
        private List<BookAirSeg> __airSegList = new List<BookAirSeg>();

        /// <summary>
        /// 连接认证成功，开始指令序列.
        /// </summary>
        protected override void StartQueue()
        {
            PnrRequire.All().Where(l => !string.IsNullOrEmpty(l.PnrCode) && (l.StatusId & (int)(PNRRequireStatus.ERROR | PNRRequireStatus.PENDDING)) != 0).OrderBy(l => l.RecordDate).ToList().ForEach(l =>
            {
                __PnrQueue.Enqueue(l);
            });
            Dequeue();
        }



        private void Dequeue()
        {
            if (__PnrQueue.Count == 0)
            {
                Disconnect();
                return;
            }
            __airSegList = new List<BookAirSeg>();              //清除上一需求行程列表
            PnrRequire model = __PnrQueue.Dequeue();
            AV(model);
        }


        private void AV(PnrRequire model)
        {
            PnrSegment segment = PnrSegment.All().Where(l => l.RequireId == model.Id && !l.IsInvalid).OrderBy(l => l.DepartureDate).FirstOrDefault();
            __CurrentSegment = segment;
            if (__CurrentSegment == null)
            {
                Dequeue();
                return;
            }
            SendStream(BuildAVCommand(segment));
        }


        /// <summary>
        /// 根据需求航段生成查询指令.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <returns>System.String.</returns>
        private string BuildAVCommand(PnrSegment segment)
        {
            StringBuilder sb = new StringBuilder(@"AVH/");
            Match m = Regex.Match(segment.FlightNo, @"([A-Z0-9]{2})\d+", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            sb.AppendFormat(@"{0}{1}", segment.Departure, segment.Arrival);
            sb.AppendFormat(@"/{0}", getDateString(segment.DepartureDate.Value));
            if (!string.IsNullOrEmpty(segment.StartRangeTime))
                sb.AppendFormat(@"/{0}", segment.StartRangeTime);
            if (m.Success)
            {
                sb.AppendFormat(@"/{0}", m.Groups[1].Value);
            }

            sb.Append(@"/D");
            return sb.ToString();
        }

        private void AV(PnrSegment model)
        {
            PnrSegment segment = PnrSegment.All().Where(l => l.RequireId == model.RequireId && l.DepartureDate >= model.DepartureDate && l.Id != model.Id && !l.IsInvalid).OrderBy(l => l.DepartureDate).FirstOrDefault();
            __CurrentSegment = segment;
            if (__CurrentSegment == null)
            {

                //待预订航段
                __airSegList.ForEach(l =>
                {
                    FireOnNotify(l.getairNo, EventType.INFO, string.Format(@"待订航段：{0}-{1}<{2}> {3}", l.getorgCity, l.getdesCity, l.getfltClass, l.departureTime.ToString(@"yyyy-MM-dd")));
                });

                Dequeue();
                return;
            }
            SendStream(BuildAVCommand(segment));
        }

        /// <summary>
        /// 插件配置文件名.
        /// </summary>
        /// <value>插件配置文件名.</value>
        protected override string SetupXmlFile
        {
            get
            {
                return @"AutoSeatPlugIn.xml";
            }
        }


        private void Assign(PnrSegment model, List<Flight> segments, string PakcetName, string PakcetResult)
        {
            //自动订座
            Match m = Regex.Match(model.FlightNo, @"([A-Z0-9]{2})\d+", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            if (m.Success)
                AssignByFlightNo(model, segments, PakcetName, PakcetResult);               //指定航班模式
            else
                AssignByCabins(model, segments, PakcetName, PakcetResult);


            //发起一下航程
            AV(model);
        }


        /// <summary>
        /// 是否含有一下页数据.
        /// </summary>
        /// <param name="Cmd">The CMD.</param>
        /// <param name="Result">The result.</param>
        /// <returns><c>true</c> if [has AV next page] [the specified CMD]; otherwise, <c>false</c>.</returns>
        private bool HasAVNextPage(string Cmd, string Result)
        {
            string queryDate = Regex.Match(Cmd, @"AVH\/[A-Z]{6}\/(\w+)\/", RegexOptions.IgnoreCase | RegexOptions.Multiline).Groups[1].Value;
            queryDate = queryDate.Substring(0, 5);
            return Regex.IsMatch(Result, queryDate, RegexOptions.IgnoreCase | RegexOptions.Multiline);
        }

        /// <summary>
        /// 根据指令航班需求选择航班.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="segments">The segments.</param>
        /// <param name="cmd">The CMD.</param>
        /// <param name="result">The result.</param>
        protected virtual void AssignByFlightNo(PnrSegment model, List<Flight> segments, string cmd, string result)
        {
            FireOnNotify(string.Format(@"{0}-{1}<{2}--{3}>", model.Departure, model.Arrival, model.FlightNo, model.CabinCode), EventType.INFO, string.Format(@"开始使用指定航班模式匹配用户需求航班及舱位", @""));
            List<PnrPassenger> passengers = PnrPassenger.All().Where(l => l.RequireId == model.RequireId).ToList();
            Flight fmodel = segments.ToList().Where(t => (t.Carbins.Where(g => g.Number == "A" || int.Parse(g.Number) >= passengers.Count).Count() > 0) && string.Format(@"{0}{1}", t.Airline, t.FlightNO) == model.FlightNo).Select(l => new Flight
            {
                FlightNO = l.FlightNO,
                DepartureAirport = l.DepartureAirport,
                ArrivalAirport = l.ArrivalAirport,
                Airline = l.Airline,
                DepartureTime = l.DepartureTime,
                FltDate = l.FltDate,
                Carbins = l.Carbins.ToList()
                .Join(Regex.Matches(model.CabinCode, @"([A-Z]\d?)", RegexOptions.IgnoreCase | RegexOptions.Multiline).Cast<Match>().ToList(), q => q.Carbin, v => v.Groups[1].Value, (q, v) => q)
                .Where(g => g.Number == "A" || int.Parse(g.Number) >= passengers.Count).ToList()
            }).FirstOrDefault();
            if (fmodel != null && fmodel.Carbins.Count > 0)
            { //预订座位
                //SendSSCommand(fmodel, passengers);
                __airSegList.Add(new BookAirSeg()
                {
                    getairNo = string.Format(@"{0}{1}", fmodel.Airline, fmodel.FlightNO),
                    getorgCity = fmodel.DepartureAirport,
                    getdesCity = fmodel.ArrivalAirport,
                    getfltClass = fmodel.Carbins.LastOrDefault().Carbin,
                    departureTime = model.DepartureDate.Value
                });
            }
            else if (fmodel == null && !HasAVNextPage(cmd, result))
            {
                model.IsInvalid = true;
                FireOnNotify(string.Format(@"{0}-{1}<{2}--{3}>", model.Departure, model.Arrival, model.FlightNo, model.CabinCode), EventType.ERROR, string.Format(@"{0}-{1}<{2}--{3}>航段无效", model.Departure, model.Arrival, model.FlightNo, model.CabinCode));
            }
            else if (HasAVNextPage(cmd, result))
            {
                SendStream(@"PN");
                return;
            }

            model.Save();
        }


        /// <summary>
        /// 预订座位.
        /// </summary>
        /// <param name="fmodel">The fmodel.</param>
        /// <param name="passengers">The passengers.</param>
        private void SendSSCommand(Flight fmodel, List<PnrPassenger> passengers)
        {

        }

        /// <summary>
        /// 根据舱位需求选择航班.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="segments">The segments.</param>
        /// <param name="cmd">The CMD.</param>
        /// <param name="result">The result.</param>
        protected virtual void AssignByCabins(PnrSegment model, List<Flight> segments, string cmd, string result)
        {
            List<PnrPassenger> passengers = PnrPassenger.All().Where(l => l.RequireId == model.RequireId).ToList();
            FireOnNotify(string.Format(@"{0}-{1}<{2}>", model.Departure, model.Arrival, model.CabinCode), EventType.INFO, string.Format(@"开始使用指定舱位模式用户需求航班及舱位", @""));
            //model.LSTFK_PNR_REQU_REFERENCE_PNR_SEGM = model.CabinCode.Split(new char[] { ',', '|', ';' }, StringSplitOptions.RemoveEmptyEntries).ToList().Select(l => new PnrRequireCode() { CabinCode=l }).ToList();
            var i = Regex.Matches(model.CabinCode, @"([A-Z0-9]{2})\:([A-Z]\d?[\,]?)+\;", RegexOptions.IgnoreCase | RegexOptions.Multiline).Cast<Match>().ToList()
                .Select(l => new PnrSegment() { FlightNo = l.Groups[1].Value, LSTFK_PNR_REQU_REFERENCE_PNR_SEGM = l.Groups[2].Captures.Cast<Capture>().Select(c => new PnrRequireCode() { CabinCode = Regex.Replace(c.Value, @"\,", string.Empty, RegexOptions.IgnoreCase) }).ToList() });
            //List<Flight> items = model.CabinCode.Split(new char[]{}
            i.ToList().ForEach(l =>
            {
                var cabins = segments.Where(s => s.Airline == l.FlightNo && (s.Carbins.Join(l.LSTFK_PNR_REQU_REFERENCE_PNR_SEGM, x => x.Carbin, y => y.CabinCode, (x, y) => new { FlightNo = string.Format(@"{0}{1}", s.Airline, s.FlightNO), x.Carbin })).Count() > 0)
                    .Select(h => new { l.FlightNo, Cabin = (h.Carbins.Where(r => Regex.IsMatch(r.Number, @"[1-9A]$", RegexOptions.IgnoreCase | RegexOptions.Multiline)).Join(l.LSTFK_PNR_REQU_REFERENCE_PNR_SEGM, x => x.Carbin, y => y.CabinCode, (x, y) => new { FlightNo = string.Format(@"{0}{1}", h.Airline, h.FlightNO), h.DepartureAirport, h.ArrivalAirport, h.DepartureTime, x.Carbin, x.Number })).ToList() })
                    .Where(h => h.Cabin.Count > 0)
                    ;
                var t = cabins.SelectMany(k => k.Cabin).Select(v => new PnrSegment()
                {
                    Arrival = v.ArrivalAirport,
                    Departure = v.DepartureAirport,
                    FlightNo = v.FlightNo,
                    DepartureDate = model.DepartureDate,
                    RequireId = long.Parse(v.DepartureTime),
                    CabinCode = v.Carbin,
                    TicketNoId = v.Number == "A" ? 10 : long.Parse(v.Number)
                }).Where(g => g.TicketNoId == 10 || g.TicketNoId >= passengers.Count).ToList();
                if (t.Count == 0 && !HasAVNextPage(cmd, result))
                {
                    FireOnNotify(string.Format(@"{0}-{1}<{2}>", model.Departure, model.Arrival, model.CabinCode), EventType.ERROR, string.Format(@"无有效航班舱位无法预定。", @""));
                    return;
                }
                else if (t.Count == 0 && HasAVNextPage(cmd, result))
                {
                    SendStream(@"PN");
                    return;
                }
                else
                {
                    //__OrderQueue.Clear();
                    t.ForEach(n =>
                    {

                        FireOnNotify(string.Format(@"{0}-{1}<{2}>", model.Departure, model.Arrival, model.CabinCode), EventType.ERROR, string.Format(@"有效航班舱位{0}-{1} {2} <{3}:{4}>。", n.Departure, n.Arrival, n.FlightNo, n.CabinCode, n.TicketNoId));
                    });
                    //TryGetSeat(passengers);
                }
            });
        }


        /// <summary>
        /// 指令结果分析.
        /// </summary>
        /// <param name="PakcetName">指令名称.</param>
        /// <param name="PakcetResult">指令结果.</param>
        protected override void ExecutePacket(string PakcetName, string PakcetResult)
        {
            FireOnNotify(PakcetName, EventType.INFO, PakcetResult);
            if (Regex.IsMatch(PakcetName, @"^(PN|AV)", RegexOptions.IgnoreCase | RegexOptions.Multiline))
            {     //航班查询指令结果处理
                List<Flight> items = new AnalysisAVH().ParseAVH(PakcetName, PakcetResult).Flights;
                if (items != null && items.Count > 0)
                {
                    Assign(__CurrentSegment, items, PakcetName, PakcetResult);
                }
            }
        }

        /// <summary>
        /// 完成插件后调用方法.
        /// </summary>
        protected override void AfterExecutePlugIn()
        {
            //base.AfterExecutePlugIn();
        }


    }
}
